package com.jyniubi.gmail.search.listener;

import com.jyniubi.gmail.common.bean.ResponseVo;
import com.jyniubi.gmail.pms.entity.*;
import com.jyniubi.gmail.search.feign.GmailPmsClient;
import com.jyniubi.gmail.search.feign.GmailWmsClient;
import com.jyniubi.gmail.search.pojo.Goods;
import com.jyniubi.gmail.search.pojo.SearchAttrValueVo;
import com.jyniubi.gmail.wms.entity.WareSkuEntity;
import com.rabbitmq.client.Channel;
import org.springframework.amqp.core.ExchangeTypes;
import org.springframework.amqp.core.Message;
import org.springframework.amqp.rabbit.annotation.Exchange;
import org.springframework.amqp.rabbit.annotation.Queue;
import org.springframework.amqp.rabbit.annotation.QueueBinding;
import org.springframework.amqp.rabbit.annotation.RabbitListener;
import org.springframework.beans.BeanUtils;
import org.springframework.data.elasticsearch.core.ElasticsearchRestTemplate;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import javax.annotation.Resource;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.stream.Collectors;


@Component
public class GoodsListener {

    @Resource
    private GmailPmsClient pmsClient;
    @Resource
    private ElasticsearchRestTemplate restTemplate;
    @Resource
    private GmailWmsClient wmsClient;

    @RabbitListener(bindings = @QueueBinding(value = @Queue("SEARCH.INSERT.QUEUE")
            ,exchange = @Exchange(value = "PMS.ITEM.EXCHANGE",ignoreDeclarationExceptions = "true",type = ExchangeTypes.TOPIC)
            ,key={"item.insert"}))
    public void syncData(Long spuId, Message message, Channel channel) throws IOException {
        if (spuId == null){
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            return;
        }
        ResponseVo<SpuEntity> spuEntityResponseVo = this.pmsClient.querySpuById(spuId);
        SpuEntity spuEntity = spuEntityResponseVo.getData();
        if (spuEntity == null){
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            return;
        }
        // 根据skuId查询sku
        ResponseVo<List<SkuEntity>> skuResponseVo = this.pmsClient.querySkusById(spuEntity.getId());
        List<SkuEntity> skuEntities = skuResponseVo.getData();
        // 判空
        if (CollectionUtils.isEmpty(skuEntities)){
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
            return;
        }
        // 查品牌
        ResponseVo<BrandEntity> brandEntityResponseVo = this.pmsClient.queryBrandById(spuEntity.getBrandId());
        BrandEntity brandEntity = brandEntityResponseVo.getData();
        ResponseVo<CategoryEntity> categoryEntityResponseVo = this.pmsClient.queryCategoryById(spuEntity.getCategoryId());
        CategoryEntity categoryEntity = categoryEntityResponseVo.getData();
        // 获取基本参数聚合字段
        ResponseVo<List<SpuAttrValueEntity>> baseSearchAttrValueResponseVo =
                this.pmsClient.querySearchAttrValuesByCidAndSpuId(categoryEntity.getId(), spuEntity.getId());
        List<SpuAttrValueEntity> baseSearchAttrValues = baseSearchAttrValueResponseVo.getData();
        this.restTemplate.save(skuEntities.stream().map(skuEntity -> {
            Goods goods = new Goods();
            goods.setSkuId(skuEntity.getId());
            goods.setTitle(skuEntity.getTitle());
            goods.setSubtitle(skuEntity.getSubtitle());
            goods.setDefaultImage(skuEntity.getDefaultImage());
            goods.setPrice(skuEntity.getPrice().doubleValue());
            goods.setCreateTime(spuEntity.getCreateTime());
            // 获取销量和是否有库存
            ResponseVo<List<WareSkuEntity>> wareSkuResponseVo = this.wmsClient.querySkuById(skuEntity.getId());
            List<WareSkuEntity> wareSkuEntities = wareSkuResponseVo.getData();
            if (!CollectionUtils.isEmpty(wareSkuEntities)){
                goods.setSales(wareSkuEntities.stream().map(WareSkuEntity::getSales).reduce((k,v)->k+v).get());
                goods.setStore(wareSkuEntities.stream().anyMatch(wareSkuEntity ->
                        wareSkuEntity.getStock()-wareSkuEntity.getStockLocked()>0));
            }
            // 获取品牌相关字段
            if (brandEntity != null){
                goods.setBrandId(brandEntity.getId());
                goods.setBrandName(brandEntity.getName());
                goods.setLogo(brandEntity.getLogo());
            }
            // 获取分类聚合字段
            if (categoryEntity !=null){
                goods.setCategoryId(categoryEntity.getId());
                goods.setCategoryName(categoryEntity.getName());
            }
            // 获取规格参数聚合字段
            ResponseVo<List<SkuAttrValueEntity>> saleSearchAttrValueResponseVo =
                    this.pmsClient.querySearchAttrValuesByCidAndSkuId(categoryEntity.getId(), skuEntity.getId());
            List<SkuAttrValueEntity> saleSearchAttrValues = saleSearchAttrValueResponseVo.getData();
            List<SearchAttrValueVo> searchAttrValueVos = new ArrayList<>();
            if (!CollectionUtils.isEmpty(saleSearchAttrValues)){
                searchAttrValueVos.addAll(saleSearchAttrValues.stream().map(skuAttrValueEntity -> {
                    SearchAttrValueVo searchAttrValueVo = new SearchAttrValueVo();
                    BeanUtils.copyProperties(skuAttrValueEntity,searchAttrValueVo);
                    return searchAttrValueVo;
                }).collect(Collectors.toList()));
            }
            if (!CollectionUtils.isEmpty(baseSearchAttrValues)){
                searchAttrValueVos.addAll(baseSearchAttrValues.stream().map(spuAttrValueEntity -> {
                    SearchAttrValueVo searchAttrValueVo = new SearchAttrValueVo();
                    BeanUtils.copyProperties(spuAttrValueEntity,searchAttrValueVo);
                    return searchAttrValueVo;
                }).collect(Collectors.toList()));
            }
            goods.setSearchAttrs(searchAttrValueVos);
            return goods;
        }).collect(Collectors.toList()));
        // 手动模式确认，防止消息丢失
        try {
            // 第一个参数是消息的deliveryTag，它是一个唯一标识符，用于RabbitMQ识别哪条消息被确认
            // 第二个参数是一个布尔值，指示是否批量确认消息。false表示只确认当前消息，而不是确认到当前为止所有未确认的消息。
            channel.basicAck(message.getMessageProperties().getDeliveryTag(),false);
        // 如果在确认消息时发生异常
        } catch (IOException e) {
            // 这行代码检查当前消息是否是重新投递的（即之前已经被投递过，但可能因为某些原因被消费者拒绝或未确认）。
            if (message.getMessageProperties().getRedelivered()){
                //如果消息是重新投递的，则使用basicReject方法拒绝这条消息。basicReject也接受两个参数：
                //第一个参数是消息的deliveryTag。
                //第二个参数是一个布尔值，指示是否将消息重新加入队列末尾以便将来重新投递。在这里，false表示不重新加入队列，即消息将被丢弃。
                channel.basicReject(message.getMessageProperties().getDeliveryTag(),false);
            }else {
                //如果消息不是重新投递的
                //则使用basicNack方法拒绝并可能重新投递这条消息。basicNack接受三个参数：
                //第一个参数是消息的deliveryTag。
                //第二个参数是一个布尔值，同样指示是否批量处理。在这里，false表示只处理当前消息。
                //第三个参数是一个布尔值，指示是否将消息重新加入队列末尾。在这里，true表示如果队列支持，消息将被重新投递。
                channel.basicNack(message.getMessageProperties().getDeliveryTag(),false,true);
            }
        }

    }
}
